home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / compiler / Back.sml < prev    next >
Encoding:
Text File  |  1997-08-18  |  30.8 KB  |  857 lines  |  [TEXT/R*ch]

  1. (*  back.sml : translation of lambda terms to lists of instructions. *)
  2.  
  3. (* 1996.07.27 -- e *)
  4.  
  5. open List Fnlib Mixture Const Lambda Prim Instruct;
  6.  
  7. (* "isReturn" determines if we're in tail call position. *)
  8.  
  9. fun isReturn (Kreturn _ :: _ )             = true
  10.   | isReturn (Klabel _ :: Kreturn _ :: _ ) = true
  11.   | isReturn _                             = false
  12. ;
  13.  
  14. (* Label generation *)
  15.  
  16. val labelCounter = ref 0;
  17.  
  18. fun resetLabel() =
  19.   labelCounter := 0
  20. ;
  21.  
  22. fun new_label() =
  23.   (incr labelCounter; !labelCounter)
  24. ;
  25.  
  26. (* the label ref in an Lshared node is used as follows:
  27.    NoLabel -> (~1) initial value
  28.    n  < 0  -> seen by the nth pass of unref
  29.    n >= 0  -> a real label, code has been emitted
  30.  Whenever a Lshared node is processed by a rewriter,
  31.  its label ref is set to !labelNotCtr. The counter is 
  32.  bumped by each rewrite in UNdeBruijn's lftexp.
  33. *)
  34.  
  35. val labelNotCtr = ref Nolabel; (* for Lshared *)
  36.  
  37. fun resetLabelNot() =
  38.   labelNotCtr := Nolabel - 1
  39. ;
  40.  
  41. fun newLabelNot() =
  42.   (decr labelNotCtr; !labelNotCtr)
  43. ;
  44.  
  45. (* Add a label to a list of instructions. *)
  46.  
  47. fun labelCode C =
  48.   case C of
  49.     Kbranch lbl :: _ =>
  50.       (lbl, C)
  51.   | Klabel lbl :: _ =>
  52.       (lbl, C)
  53.   | _ =>
  54.       let val lbl = new_label()
  55.       in (lbl, Klabel lbl :: C) end
  56. ;
  57.  
  58. (* Generate a branch to the given list of instructions. *)
  59.  
  60. fun makeBranch C =
  61.   case C of
  62.     (return as Kreturn _) :: _ => (return, C)
  63.   | (branch as Kbranch _) :: _ => (branch, C)
  64.   | Kraise :: _  => (Kraise, C)
  65.   | Klabel _ :: (return as Kreturn _) :: _ => (return, C)
  66.   | Klabel lbl :: _ => (Kbranch lbl, C)
  67.   | _ =>
  68.       let val lbl = new_label()
  69.       in (Kbranch lbl, Klabel lbl :: C) end
  70. ;
  71.  
  72. (* Discard all instructions up to the next label. *)
  73.  
  74. fun discardDeadCode C =
  75.   case C of
  76.     [] => []
  77.   | Klabel _ :: _      => C
  78.   | Krestart :: _      => C
  79.   | Kset_global _ :: _ => C
  80.   | _ :: rest => discardDeadCode rest
  81. ;
  82.  
  83. (* compile time model of runtime environment
  84.      mapping Lvar id to stack or heapenv offsets
  85.    fv is freevars, a list; position of negative id is the runtime env index
  86.    va is vararray, an array mapping positive ids to stack index
  87. *)
  88.  
  89. val nullEnv = ([],Array.array(256,(~1))) : int list * int Array.array;
  90.  
  91. fun makeEnv fv maxstk = (fv, Array.array(maxstk,(~1)));
  92.  
  93. fun findEnv (fv,va) sz n =
  94.   if n < 0
  95.   then let fun f i [] = fatalError ("findEnv fv n: " ^ (makestring n))
  96.              | f i (x::r) = if x = n then Kenvacc i else f (i + 1) r
  97.        in f 0 fv end
  98.   else let val i = Array.sub (va,n)
  99.        in if i < 0 then fatalError "findEnv va1" else Kaccess (sz - i) end
  100.        handle Subscript => fatalError ("findEnv va2 n: " ^ (makestring n))
  101. ;
  102. fun findStk (fv,va) sz n =
  103.   if n < 0
  104.   then fatalError ("findStk n: " ^ (makestring n))
  105.   else let val i = Array.sub (va,n)
  106.        in if i < 0 then fatalError "findStk va1" else Kassign (sz - i) end
  107.        handle Subscript => fatalError ("findStk va2 n: " ^ (makestring n))
  108. ;
  109.  
  110. (* e -- note: this destroys the env *)
  111.  
  112. fun bindEnv (fv,va) n z =
  113.   let val n' = n + 1
  114.   in
  115.     Array.update (va,n,z); (* not n' !? *)
  116.     n'
  117.   end
  118.   handle Subscript => fatalError "bindEnv"
  119. ;
  120.  
  121. (* *)
  122.  
  123. fun addPop n C =
  124.   if n = 0
  125.   then C
  126.   else
  127.     case C of
  128.       Kpop m :: C    => addPop (n + m) C
  129.     | Kreturn m :: C => Kreturn (n + m) :: C
  130.     | Kraise :: _    => C
  131.     | _              => Kpop n :: C
  132. ;
  133.  
  134. (* Generate a jump through table, unless unnecessary. *)
  135.  
  136. exception JumpOut;
  137.  
  138. fun add_SwitchTable switchtable C =
  139.   let open Array infix 9 sub in
  140.     (for (fn i => if (switchtable sub i) <> (switchtable sub 0) then
  141.                     raise JumpOut
  142.                   else ())
  143.          1 (length switchtable - 1);
  144.      case C of
  145.          Klabel lbl :: C1 =>
  146.            if lbl = (switchtable sub 0) then C
  147.            else
  148.              Kbranch (switchtable sub 0) :: discardDeadCode C
  149.        | _ =>
  150.           Kbranch (switchtable sub 0) :: discardDeadCode C)
  151.     handle JumpOut =>
  152.       Kswitch switchtable :: C
  153.   end;
  154.  
  155. (* Compiling N-way integer branches *)
  156.  
  157. (* Input: a list of (key, action) pairs, where keys are integers. *)
  158. (* Output: a decision tree with the format below *)
  159.  
  160. datatype DecisionTree =
  161.     DTfail
  162.   | DTinterval of DecisionTree * Decision * DecisionTree
  163.  
  164. withtype Decision =
  165. {
  166.   low: int,
  167.   act: Lambda Array.array,
  168.   high: int
  169. };
  170.  
  171. fun compileNBranch int_of_key clauses =
  172.   let open Array infix 9 sub
  173.       val clauses_i =
  174.         map (fn (key, act) => (int_of_key key : int, act)) clauses
  175.       val clauses_s =
  176.         Sort.sort (fn (key1, act1) => fn (key2, act2) => key1 <= key2)
  177.                   clauses_i
  178.       val keyv = Array.fromList (map fst clauses_s)
  179.       val actv = Array.fromList (map snd clauses_s)
  180.       val n    = length keyv
  181.       fun extractAct start stop =
  182.         let val a =
  183.               array((keyv sub stop) - (keyv sub start) + 1, Lstaticfail)
  184.         in
  185.           for (fn i =>
  186.                  update(a, (keyv sub i) - (keyv sub start), actv sub i))
  187.               start stop;
  188.           a
  189.         end
  190.       (* Now we partition the set of keys keyv into maximal
  191.          dense enough segments. A segment is dense enough
  192.          if its span (max point - min point) is less
  193.          than four times its size (number of points). *)
  194.       fun partition start =
  195.         if start >= n then [] else
  196.         let val stop = ref (n-1) in
  197.           while (keyv sub !stop) - (keyv sub start) >= 255 orelse
  198.                 (keyv sub !stop) - (keyv sub start) > 4 * (!stop - start)
  199.           do decr stop;
  200.           (* We've found a segment that is dense enough.
  201.              In the worst case, !stop = start and the segment is
  202.              a single point *)
  203.           (* Now build the vector of actions *)
  204.           { low = keyv sub start,
  205.             act = extractAct start (!stop),
  206.             high = keyv sub !stop } :: partition (!stop + 1)
  207.         end
  208.       val part = Array.fromList (partition 0)
  209.       (* We build a balanced binary tree *)
  210.       fun make_tree start stop =
  211.         if start > stop then
  212.           DTfail
  213.         else
  214.           let val middle = (start + stop) div 2 in
  215.             DTinterval(make_tree start (middle-1),
  216.                        part sub middle,
  217.                        make_tree (middle+1) stop)
  218.           end
  219.   in make_tree 0 (length part - 1) end
  220. ;
  221.  
  222. (* To check if a switch construct contains tags that are unknown at
  223.    compile-time (i.e. exception tags). *)
  224.  
  225. fun switch_contains_exception_tags clauses =
  226.   exists (fn (EXNtag _, _) => true | _ => false) clauses
  227. ;
  228.  
  229. (* Inversion of a boolean test ( < becomes >= and so on) *)
  230.  
  231. val invertPrimTest = fn
  232.     PTeq => PTnoteq
  233.   | PTnoteq => PTeq
  234.   | PTnoteqimm x => fatalError "invertPrimTest"
  235.   | PTlt => PTge
  236.   | PTle => PTgt
  237.   | PTgt => PTle
  238.   | PTge => PTlt
  239. ;
  240.  
  241. val invertBoolTest = fn
  242.     Peq_test => Pnoteq_test
  243.   | Pnoteq_test => Peq_test
  244.   | Pint_test t => Pint_test(invertPrimTest t)
  245.   | Pfloat_test t => Pfloat_test(invertPrimTest t)
  246.   | Pstring_test t => Pstring_test(invertPrimTest t)
  247.   | Pword_test t => Pword_test(invertPrimTest t)
  248.   | Pnoteqtag_test t => fatalError "invertBoolTest"
  249. ;
  250.  
  251. (* Production of an immediate test *)
  252.  
  253. val testForAtom = fn
  254.     INTscon x => Pint_test(PTnoteqimm x)
  255.   | WORDscon x => Pword_test(PTnoteqimm x)
  256.   | CHARscon x => Pint_test(PTnoteqimm (Char.ord x))
  257.   | REALscon x => Pfloat_test(PTnoteqimm x)
  258.   | STRINGscon x => Pstring_test(PTnoteqimm x)
  259. ;
  260.  
  261. (* To keep track of function bodies that remain to be compiled. *)
  262.  
  263. (* ... a stack of (lbl, nargs, free var ids list, max id, body) *)
  264.  
  265. val stillToCompile  = (Stack.new () : (int * int * int list * int * Lambda) Stack.t);
  266.  
  267. (* translation of lambda-deBruijn to lambda-merged-stkdepth
  268.    this requires giving all the Lvars unique ids within the enclosing function
  269.     [well, kinda. unique within their scope, anyway]
  270.    to do this requires maintaining an rstack depth model
  271.      then the translation is simply: deBruijn -> depth - deBruijn - 1
  272.  
  273.    all functions are lifted to top level simultaneously
  274.     as a result all free variables have negative ids
  275.      a closure map is constructed for compileRest
  276.    an Lfn is replaced with the closure constuction code
  277. *)
  278.  
  279. fun UNdeBruijn exp =
  280.   let
  281.     exception Refs'R'Us
  282.     val fv = ref []
  283.     val md = ref 0
  284.  
  285.     fun ins x [] = [x]
  286.       | ins x (ls as (y::r)) =
  287.           if x > y then x :: ls
  288.           else if x = y then ls
  289.           else let val z = ins x r in if z = r then ls else y :: z end
  290.  
  291.     fun extClo id =
  292.       if id >= 0 then ()
  293.       else fv := (ins id (!fv))
  294.  
  295.     fun unref i exp = (* turn refs from heap into stack cells *)
  296.       case exp of
  297.         Lvar n => (* oops, maybe it's a real reference *)
  298.           if n = i then raise Refs'R'Us else exp
  299.       | Lassign (n,exp') => (* we'd only see n = i in an Lshared node? *)
  300.           Lassign(n, unref i exp')
  301.       | Lconst cst =>
  302.           exp
  303.       | Lapply(body, args) =>
  304.           Lapply(unref i body, List.map (unref i) args)
  305.       | Lfn body =>
  306.          fatalError "UNdeBruijn/unref Lfn!?"
  307.       | Llet(args, body) =>
  308.           Llet(List.map (unref i) args, unref i body)
  309.       | Lletrec(args, body) =>
  310.           Lletrec(List.map (unref i) args, unref i body)
  311.       | Lprim(Pfield 0, [opt as (Lvar v)]) =>
  312.           if v = i
  313.           then opt
  314.           else exp
  315.       | Lprim(Psetfield 0, [Lvar v, e]) =>
  316.           if v = i
  317.           then Lassign (i, unref i e)            (* new *)
  318.           else Lprim(Psetfield 0, [Lvar v, unref i e])
  319.       | Lprim(p, explist) =>
  320.           Lprim(p, List.map (unref i) explist)
  321.       | Lstatichandle(body, handler) =>
  322.           Lstatichandle(unref i body, unref i handler)
  323.       | Lstaticfail =>
  324.           Lstaticfail
  325.       | Lhandle(body, handler) =>
  326.           Lhandle(unref i body, unref i handler)
  327.       | Lif(cond, ifso, ifnot) =>
  328.           Lif(unref i cond, unref i ifso, unref i ifnot)
  329.       | Lseq(exp1, exp2) =>
  330.           Lseq(unref i exp1, unref i exp2)
  331.       | Lwhile(cond, body) =>
  332.           Lwhile(unref i cond, unref i body)
  333.       | Landalso(exp1, exp2) =>
  334.           Landalso(unref i exp1, unref i exp2)
  335.       | Lorelse(exp1, exp2) =>
  336.           Lorelse(unref i exp1, unref i exp2)
  337.       | Lcase(arg, clauses) =>
  338.           Lcase(unref i arg,
  339.                 List.map (fn (tag,act) => (tag, unref i act)) clauses)
  340.       | Lswitch(size, arg, clauses) =>
  341.           Lswitch(size, unref i arg, 
  342.                 List.map (fn (tag,act) => (tag, unref i act)) clauses)
  343.       | Lunspec =>
  344.           Lunspec
  345.       | Lshared(exp_ref, lbl_ref) =>
  346.           if !lbl_ref <> !labelNotCtr
  347.           then ( lbl_ref := !labelNotCtr; 
  348.                  exp_ref := unref i (!exp_ref);
  349.                  exp )
  350.           else exp
  351.  
  352.     fun lftexp depth exp =
  353.       (if depth > !md then md := depth else ();
  354.       case exp of
  355.         Lvar n =>
  356.           let val id = (depth - n - 1)
  357.           in extClo id; Lvar id end
  358.       | Lassign (n,exp') =>
  359.           let val id = (depth - n - 1)
  360.           in extClo id; Lassign (id,lftexp depth exp') end
  361.       | Lconst cst => exp
  362.       | Lapply(body, args) => Lapply(lftexp depth body, List.map (lftexp depth) args)
  363.       | Lfn body =>
  364.          let val (qfv, exp') = UNdeBruijn exp (* recurse *)
  365.          in if qfv > 0 then lftexp depth exp' else exp' end
  366.       (* Optimize special case arising from #lab arg *)
  367.       | Llet([arg], Lprim(p, [Lvar 0])) => 
  368.          Lprim(p, [lftexp depth arg])
  369.       | Llet(args, body) =>
  370.           let fun opt_refs body' i [] acc =
  371.                     Llet(acc, body')
  372.                 | opt_refs body' i (* do we care what the tag is? *)
  373.                           ((exp as Lprim(Pmakeblock(CONtag(refTag,1)),[e]))
  374.                            ::rest) acc =
  375.                    (let val lnot = newLabelNot()
  376.                         (* val () = BasicIO.print ("Optref: " ^ (makestring lnot)) *)
  377.                         val acc' = List.map (unref i) acc
  378.                         val body'' = unref i body'
  379.                     in (* BasicIO.print " $\n"; *)
  380.                        opt_refs body'' (i - 1) rest (e::acc')
  381.                     end
  382.                     handle Refs'R'Us =>
  383.                       ( (* BasicIO.print ("\n"); *)
  384.                        opt_refs body' (i - 1) rest (exp::acc) ) )
  385.                 | opt_refs body' i (exp::rest) acc =
  386.                     opt_refs body' (i - 1) rest (exp::acc)
  387.               fun lift_args ea [] acc =
  388.                     opt_refs (lftexp ea body) (ea - 1) acc []
  389.                 | lift_args ea (exp::rest) acc =
  390.                     lift_args (ea + 1) rest ((lftexp ea exp) :: acc)
  391.           in lift_args depth args [] end
  392.       | Lletrec(args, body) =>
  393.           let val ea = depth + (List.length args)
  394.           in Lletrec(List.map (lftexp ea) args, lftexp ea body) end
  395.       | Lprim(p, explist) => Lprim(p, List.map (lftexp depth) explist)
  396.       | Lstatichandle(body, handler) =>
  397.           Lstatichandle(lftexp depth body, lftexp depth handler)
  398.       | Lstaticfail => Lstaticfail
  399.       | Lhandle(body, handler) =>
  400.           Lhandle(lftexp depth body, lftexp (depth + 1) handler)
  401.       | Lif(cond, ifso, ifnot) => Lif(lftexp depth cond, lftexp depth ifso, lftexp depth ifnot)
  402.       | Lseq(exp1, exp2) => Lseq(lftexp depth exp1, lftexp depth exp2)
  403.       | Lwhile(cond, body) => Lwhile(lftexp depth cond, lftexp depth body)
  404.       | Landalso(exp1, exp2) => Landalso(lftexp depth exp1, lftexp depth exp2)
  405.       | Lorelse(exp1, exp2) => Lorelse(lftexp depth exp1, lftexp depth exp2)
  406.       | Lcase(arg, clauses) =>
  407.           Lcase(lftexp depth arg, List.map (fn (tag,act) => (tag, lftexp depth act)) clauses)
  408.       | Lswitch(size, arg, clauses) =>
  409.           Lswitch(size, lftexp depth arg, List.map (fn (tag,act) => (tag, lftexp depth act)) clauses)
  410.       | Lunspec => Lunspec
  411.       | Lshared(exp_ref, lbl_ref) =>
  412.           if !lbl_ref = Nolabel
  413.           then ( lbl_ref := !labelNotCtr; 
  414.                  exp_ref := lftexp depth (!exp_ref);
  415.                  exp )
  416.           else exp
  417.       )
  418.  
  419.     fun liftbd depth exp = (* called with the body of an Lfn *)
  420.       let val exp' = lftexp depth exp
  421.           val lbl = new_label()
  422.           val fre = List.map (fn id => Lvar ((~1) - id)) (!fv)
  423.           val qfv = List.length fre
  424.           val exp'' = Lprim(Pclosure (lbl, qfv), fre)
  425.       in
  426.         Stack.push (lbl, depth, !fv, !md, exp') stillToCompile;
  427.         (* Pr_lam.printLam exp';  -- e *)
  428.         (* Pr_lam.printLam exp''; -- e *)
  429.         (qfv, exp'')
  430.       end
  431.  
  432.     fun liftfn depth exp =
  433.       case exp of
  434.         Lfn body => liftfn (depth + 1) body
  435.       | _        => liftbd depth exp
  436.  
  437.     fun liftit depth exp =
  438.       case exp of
  439.         Lfn body => liftfn (depth + 1) body
  440.       | _        => let val exp' = lftexp depth exp in (List.length (!fv), exp') end
  441.  
  442.   in liftit 0 exp end
  443. ;
  444.  
  445. (* The translator from lambda terms to lists of instructions.
  446.  
  447.    env: the map from Lvar ids to stackptr offsets; side-effected
  448.    staticfail : the pair (label,sz) where Lstaticfail must branch.
  449.    sz: the current runtime stack model depth  (includes codegen temporaries)
  450.    dp: the depth of the Front.sml stack model (excludes codegen temporaries)
  451.    exp : the lambda term to compile.
  452.    C : the continuation, i.e. the code that follows the code for lambda.
  453.  
  454.    The tests on the continuation detect tail-calls and avoid jumps to jumps,
  455.    or jumps to function returns.
  456.  
  457. *)
  458.  
  459. fun compileExp env staticfail =
  460.   let
  461.     open Array infix 9 sub
  462.  
  463.     fun compexp sz dp exp C =
  464.       case exp of
  465.         Lvar n =>
  466.           (findEnv env sz n) :: C
  467.       | Lassign (n,exp') =>
  468.           compexp sz dp exp' ((findStk env sz n) :: C)
  469.       | Lconst cst =>
  470.           (case C of
  471.                Kquote _      :: _ => C
  472.              | Kget_global _ :: _ => C
  473.              | Kaccess _     :: _ => C
  474.              | Kenvacc _     :: _ => C
  475.              | _ => Kquote cst :: C)
  476.       | Lapply(body, args) =>
  477.           let val na = List.length args
  478.           in
  479.             if isReturn C
  480.             then compExpList sz dp args
  481.                    (Kpush :: compexp (sz + na) dp body
  482.                                (Kappterm (na, sz + na) :: discardDeadCode C))
  483.             else if na < 5
  484.             then compExpList sz dp args
  485.                    (Kpush :: compexp (sz + na) dp body (Kapply na :: C))
  486.             else
  487.         (* 3 is the number of stack positions used by Kpush_retaddr *)
  488.               let val (lbl, C1) = labelCode C
  489.               in Kpush_retaddr lbl ::
  490.                    compExpList (sz + 3) dp args
  491.                      (Kpush :: compexp (sz + 3 + na) dp body (Kapply na :: C1))
  492.               end
  493.           end
  494.       | Lfn body =>
  495.           fatalError "compileExp Lfn!?"
  496.       (* Special case arising from val _ = arg *)
  497.       | Llet([arg], Lunspec) => compexp sz dp arg C
  498.       | Llet(args, body) =>
  499.           let val na = List.length args
  500.               fun complet sz dp [] =
  501.                     compexp sz dp body (addPop na C)
  502.                 | complet sz dp (exp::rest) =
  503.                     let val z = sz + 1
  504.                     in
  505.                       compexp sz dp exp 
  506.                       (Kpush :: complet z (bindEnv env dp z) rest)
  507.                     end
  508.           in complet sz dp args end
  509.       | Lletrec([e as Lprim(Pclosure (lbl, csz), fre)], body) =>
  510.           let val z = sz + 1
  511.               val d = bindEnv env dp z
  512.               val C1 = Kpush :: compexp z d body (addPop 1 C)
  513.           in
  514.             case fre of
  515.           (Lvar n)::rest =>
  516.                 if n = dp
  517.                 then compExpList sz dp rest (Kclosurerec (lbl, csz) :: C1)
  518.                 else compExpList sz dp  fre (Kclosure (lbl, csz) :: C1)
  519.         | [] =>  Kclosure (lbl, 0) :: C1
  520.         |  _ =>  fatalError "compileExp: malformed Letrec!?"
  521.           end
  522.       | Lletrec(args, body) =>
  523.           let val na = List.length args
  524.               fun comparg sz dp i [] =
  525.                     compexp sz dp body (addPop na C)
  526.                 | comparg sz dp i ((e as Lprim(Pclosure (lbl, csz), fre)) :: r) =
  527.                     compexp sz dp e
  528.                       (Kpush :: Kaccess i :: Kprim Pupdate :: comparg sz dp (i-1) r)
  529.                 | comparg _ _ _ _ =
  530.                     fatalError "compileExp Lletrec"
  531.               fun initarg sz dp [] =
  532.                     comparg sz dp na args
  533.                 | initarg sz dp (Lprim(Pclosure (lbl, csz), fre) :: r) =
  534.                     let val z = sz + 1
  535.                     in
  536.                       Kprim (Pdummy csz) :: Kpush :: initarg z (bindEnv env dp z) r
  537.                     end
  538.                 | initarg _ _ (e::_) =
  539.                     ((* Pr_lam.printLam e; *)
  540.                      fatalError "compileExp Lletrec")
  541.           in
  542.             initarg sz dp args
  543.           end
  544.       | Lprim(Psmladdint, [exp, Lconst(ATOMsc(INTscon 1))]) =>
  545.       compexp sz dp exp (Kprim Psmlsuccint :: C)
  546.       | Lprim(Psmlsubint, [exp, Lconst(ATOMsc(INTscon 1))]) =>
  547.       compexp sz dp exp (Kprim Psmlpredint :: C)
  548.       | Lprim(Pget_global uid, []) =>
  549.             Kget_global uid :: C
  550.       | Lprim(Pset_global uid, [exp]) =>
  551.             compexp sz dp exp (Kset_global uid :: C)
  552.       | Lprim(Pfield i, explist) =>
  553.             compExpListLR sz dp explist (Kgetfield i :: C)
  554.       | Lprim(Psetfield i, explist) =>
  555.             compExpListLR sz dp explist (Ksetfield i :: C)
  556.       | Lprim(Pmakeblock tag, explist) =>
  557.             compExpListLR sz dp explist 
  558.                             (Kmakeblock(tag, List.length explist) :: C)
  559.       | Lprim(Pnot, [exp]) =>
  560.           (case C of
  561.                Kbranchif lbl :: C' =>
  562.                  compexp sz dp exp (Kbranchifnot lbl :: C')
  563.              | Kbranchifnot lbl :: C' =>
  564.                  compexp sz dp exp (Kbranchif lbl :: C')
  565.              | _ =>
  566.                  compexp sz dp exp (Kprim Pnot :: C))
  567.       | Lprim(p as Ptest tst, explist) =>
  568.           (case C of
  569.                Kbranchif lbl :: C' =>
  570.                  compExpListLR sz dp explist (Ktest(tst,lbl) :: C')
  571.              | Kbranchifnot lbl :: C' =>
  572.                  compExpListLR sz dp  explist (Ktest(invertBoolTest tst,lbl) :: C')
  573.              | _ =>
  574.                  compExpListLR sz dp  explist (Kprim p :: C))
  575.       | Lprim(Praise, explist) =>
  576.             compExpListLR sz dp explist (Kraise :: discardDeadCode C)
  577.       | Lprim(Pclosure (lbl, csz), explist) =>
  578.             compExpList sz dp explist (Kclosure (lbl, csz) :: C)
  579.       (* This enables merging of pop, return, etc *)
  580.       | Lprim(Pidentity, explist) =>
  581.             compExpListLR sz dp explist C
  582.       | Lprim(p, explist) =>
  583.             compExpListLR sz dp explist (Kprim p :: C)
  584.       | Lstatichandle(body, Lstaticfail) =>
  585.             compexp sz dp body C
  586.       | Lstatichandle(body, handler) =>
  587.           let val (branch1, C1) = makeBranch C
  588.               val (handle2, C2) = labelCode (compexp sz dp handler C1)
  589.           in
  590.             compileExp env (handle2, sz) sz dp body 
  591.                    (branch1 :: discardDeadCode C2)
  592.           end
  593.       | Lstaticfail =>
  594.           let val (lbl,tsz) = staticfail
  595.           in addPop (sz - tsz) (Kbranch lbl :: discardDeadCode C) end
  596.       | Lhandle(body, handler) =>
  597.           let val (branch1, C1) = makeBranch C
  598.               val lbl2 = new_label()
  599.               val z = sz + 1
  600.           in
  601.             Kpushtrap lbl2 ::
  602.               compexp (sz + 4) dp body
  603.                 (Kpoptrap :: branch1
  604.                    :: Klabel lbl2 :: Kpush 
  605.                        :: compexp z (bindEnv env dp z) handler (addPop 1 C1))
  606.           end
  607.       | Lif(cond, ifso, ifnot) =>
  608.             compTest2 sz dp cond ifso ifnot C
  609.       | Lseq(exp1, exp2) =>
  610.             compexp sz dp exp1 (compexp sz dp exp2 C)
  611.       | Lwhile(cond, body) =>
  612.           let val lbl2 = new_label() 
  613.               val (lbl1, C1) = labelCode (compexp sz dp cond
  614.                                             (Kbranchif lbl2 :: Kquote constUnit :: C))
  615.           in
  616.             Kbranch lbl1 :: Klabel lbl2 :: Kcheck_signals :: compexp sz dp body C1
  617.           end
  618.       | Landalso(exp1, exp2) =>
  619.           (case C of
  620.                Kbranch lbl :: _  =>
  621.                  compexp sz dp exp1 (Kstrictbranchifnot lbl :: compexp sz dp exp2 C)
  622.              | Kbranchifnot lbl :: _ =>
  623.                  compexp sz dp exp1 (Kbranchifnot lbl :: compexp sz dp exp2 C)
  624.              | Kbranchif lbl :: C' =>
  625.                  let val (lbl1, C1) = labelCode C' in
  626.                    compexp sz dp exp1 (Kbranchifnot lbl1 ::
  627.                                  compexp sz dp exp2 (Kbranchif lbl :: C1))
  628.                  end
  629.              | Klabel lbl :: _ =>
  630.                  compexp sz dp exp1 (Kstrictbranchifnot lbl :: compexp sz dp exp2 C)
  631.              | _ =>
  632.                  let val lbl = new_label() in
  633.                    compexp sz dp exp1 (Kstrictbranchifnot lbl ::
  634.                                  compexp sz dp exp2 (Klabel lbl :: C))
  635.                  end)
  636.       | Lorelse(exp1, exp2) =>
  637.           (case C of
  638.                Kbranch lbl :: _  =>
  639.                  compexp sz dp exp1 (Kstrictbranchif lbl :: compexp sz dp exp2 C)
  640.              | Kbranchif lbl :: _  =>
  641.                  compexp sz dp exp1 (Kbranchif lbl :: compexp sz dp exp2 C)
  642.              | Kbranchifnot lbl :: C' =>
  643.                  let val (lbl1, C1) = labelCode C' in
  644.                    compexp sz dp exp1 (Kbranchif lbl1 ::
  645.                                  compexp sz dp exp2 (Kbranchifnot lbl :: C1))
  646.                  end
  647.              | Klabel lbl :: _ =>
  648.                  compexp sz dp exp1 (Kstrictbranchif lbl :: compexp sz dp exp2 C)
  649.              | _ =>
  650.                  let val lbl = new_label() in
  651.                    compexp sz dp exp1 (Kstrictbranchif lbl ::
  652.                                  compexp sz dp exp2 (Klabel lbl :: C))
  653.                  end)
  654.  
  655.       | Lcase(arg, clauses) =>
  656.           let val C1 =
  657.             if case clauses of
  658.                    (INTscon _, _) :: _ => true
  659.                  | (WORDscon _, _) :: _ => true
  660.                  | (CHARscon _, _) :: _ => true
  661.                  | _ => false
  662.             then
  663.               compDecision sz dp (compileNBranch intOfAtom clauses) C
  664.             else
  665.               compTests sz dp
  666.                 (map (fn (cst, act) => (testForAtom cst, act)) clauses) C
  667.           in compexp sz dp arg C1 end
  668.  
  669.       | Lswitch(1, arg, [(CONtag(_,_), exp)]) =>
  670.           compexp sz dp exp C
  671.           (* We assume the argument to be safe (not producing side-effects
  672.              and always terminating),
  673.              because switches are generated only by the match compiler *)
  674.       | Lswitch(2, arg, [(CONtag(0,_), exp0)]) =>
  675.           compTest2 sz dp arg Lstaticfail exp0 C
  676.       | Lswitch(2, arg, [(CONtag(1,_), exp1)]) =>
  677.           compTest2 sz dp arg exp1 Lstaticfail C
  678.       | Lswitch(2, arg, [(CONtag(0,_), exp0), (CONtag(1,_), exp1)]) =>
  679.           compTest2 sz dp arg exp1 exp0 C
  680.       | Lswitch(2, arg, [(CONtag(1,_), exp1), (CONtag(0,_), exp0)]) =>
  681.           compTest2 sz dp arg exp1 exp0 C
  682.       | Lswitch(size, arg, clauses) =>
  683.           let val C1 =
  684.             if switch_contains_exception_tags clauses then
  685.               compTests sz dp
  686.                 (map (fn (tag,act) => (Pnoteqtag_test tag, act)) clauses) C
  687.             else if List.length clauses >= size - 5 then
  688.               Kprim Ptag_of :: compDirectSwitch sz dp size clauses C
  689.             else
  690.               Kprim Ptag_of ::
  691.                 compDecision sz dp (compileNBranch intOfAbsoluteTag clauses) C
  692.           in compexp sz dp arg C1 end
  693.       | Lunspec =>
  694.           C
  695.       | Lshared(exp_ref, lbl_ref) =>
  696.           if !lbl_ref < 0 then
  697.             let val (lbl, C1) = labelCode (compexp sz dp (!exp_ref) C)
  698.             in
  699.               lbl_ref := lbl; C1
  700.             end
  701.           else
  702.             Kbranch (!lbl_ref) :: discardDeadCode C
  703.  
  704.     (* Compile right-left evaluation of args of functions *)
  705.     and compExpList' sz dp [] C = C
  706.       | compExpList' sz dp [exp] C = compexp sz dp exp C
  707.       | compExpList' sz dp (exp::rest) C =
  708.           compExpList' (sz - 1) dp rest (Kpush :: compexp sz dp exp C)
  709.  
  710.     and compExpList sz dp ls C = 
  711.     compExpList' (sz + List.length ls - 1) dp ls C
  712.  
  713.     (* Compile left-right evaluation of args of primitives *)
  714.     and compExpListLR' sz dp [] C = C
  715.       | compExpListLR' sz dp [exp] C = compexp sz dp exp C
  716.       | compExpListLR' sz dp (exp::rest) C =
  717.     compexp sz dp exp (Kpush :: compExpListLR' (sz + 1) dp rest C)
  718.  
  719.     and compExpListLR sz dp ls C = compExpListLR' sz dp ls C
  720.  
  721.     and compTest2 sz dp cond ifso ifnot C =
  722.       let val (sflbl,sftsz) = staticfail
  723.           val Cc = 
  724.             if ifnot = Lconst constUnit
  725.             then let val (lbl, C1) = labelCode C
  726.                  in Kstrictbranchifnot lbl :: compexp sz dp ifso C1 end
  727.             else
  728.             if ifso = Lstaticfail andalso sz = sftsz
  729.             then Kbranchif sflbl :: compexp sz dp ifnot C
  730.             else
  731.             if ifnot = Lstaticfail andalso sz = sftsz
  732.             then Kbranchifnot sflbl :: compexp sz dp ifso C
  733.             else
  734.               let val (branch1, C1) = makeBranch C
  735.                   val (lbl2, C2) = labelCode (compexp sz dp ifnot C1)
  736.               in
  737.                 Kbranchifnot lbl2 :: compexp sz dp ifso 
  738.                                      (branch1 :: discardDeadCode C2)
  739.               end
  740.       in
  741.         compexp sz dp cond Cc
  742.       end
  743.  
  744.     and compTests sz dp clauses C =
  745.       let val (branch1, C1) = makeBranch C
  746.           val (sflbl,sftsz) = staticfail
  747.           val () = if sz <> sftsz then fatalError "compTests sz" else () (* e -- assert ?? *)
  748.           fun comp [] =
  749.                 fatalError "compTests"
  750.             | comp [(test,exp)] =
  751.                 Ktest(test, sflbl) :: compexp sz dp exp C1
  752.             | comp ((test,exp)::rest) =
  753.                 let val lbl = new_label() in
  754.                   Ktest(test, lbl) :: 
  755.                     compexp sz dp exp (branch1 :: Klabel lbl :: comp rest)
  756.                 end
  757.       in comp clauses end
  758.  
  759.     and compSwitch sz dp v branch1 C =
  760.       let val (sflbl,sftsz) = staticfail
  761.           val switchtable = array(length v, sflbl)
  762.           fun comp_cases n =
  763.             if n >= length v then
  764.               C
  765.             else
  766.               let val (lbl, C1) = 
  767.           labelCode (compexp sz dp (v sub n) 
  768.                  (branch1 :: discardDeadCode (comp_cases (n+1))))
  769.               in 
  770.                 update(switchtable, n, lbl); C1 
  771.               end
  772.       in add_SwitchTable switchtable (discardDeadCode(comp_cases 0)) end
  773.  
  774.     and compDecision sz dp tree C =
  775.       let val (branch1, C1) = makeBranch C
  776.           val (sflbl,sftsz) = staticfail
  777.           val () = if sz <> sftsz then fatalError "compDecision sz" else () (* e -- assert ?? *)
  778.           fun comp_dec DTfail C =
  779.                 Kbranch sflbl :: discardDeadCode C
  780.             | comp_dec (DTinterval(left, dec, right)) C =
  781.                 let val (lbl_right, Cright) =
  782.                       case right of
  783.                           DTfail => (sflbl, C)
  784.                         | _      => labelCode (comp_dec right C)
  785.                     val (lbl_left, Cleft) =
  786.                       case left of
  787.                           DTfail => (sflbl, Cright)
  788.                         | _ =>      labelCode (comp_dec left Cright)
  789.                     val {low, act, high} = dec
  790.                 in
  791.                   Kbranchinterval(low, high, lbl_left, lbl_right) ::
  792.                   (case length act of
  793.                        1 => compexp sz dp (act sub 0)
  794.                                           (branch1 :: discardDeadCode Cleft)
  795.                      | _ => compSwitch sz dp act branch1 Cleft)
  796.                 end
  797.       in comp_dec tree C1 end
  798.  
  799.     and compDirectSwitch sz dp size clauses C =
  800.       let val (branch1, C1) = makeBranch C
  801.           val (sflbl,sftsz) = staticfail
  802.           val () = if sz <> sftsz andalso size <> (List.length clauses)
  803.                    then fatalError "compDirectSwitch sz" else () (* e -- assert ?? *)
  804.           val switchtable = array(size, sflbl)
  805.           fun comp_case [] =
  806.                 fatalError "compDirectSwitch"
  807.             | comp_case [(tag, exp)] =
  808.                 let val (lbl, C2) = labelCode (compexp sz dp exp C1) in
  809.                   update(switchtable, intOfAbsoluteTag tag, lbl);
  810.                   C2
  811.                 end
  812.             | comp_case ((tag, exp) :: rest) =
  813.                 let val (lbl, C2) =
  814.                   labelCode (compexp sz dp exp 
  815.                  (branch1 :: discardDeadCode (comp_case rest)))
  816.                 in
  817.                   update(switchtable, intOfAbsoluteTag tag, lbl);
  818.                   C2
  819.                 end
  820.       in add_SwitchTable switchtable (discardDeadCode(comp_case clauses)) end
  821.  
  822.   in compexp end
  823. ;
  824.  
  825. fun compileRest C =
  826.   let val (lbl, nargs, fv, maxstk, exp) = Stack.pop stillToCompile
  827.       val env = makeEnv fv maxstk
  828.       fun inienv a sz = if a < nargs
  829.                         then inienv (bindEnv env a sz) (sz - 1)
  830.                         else ()
  831.       val () = inienv 0 nargs
  832.       val C' = compileExp env (Nolabel, 0) nargs nargs exp 
  833.                             (Kreturn nargs :: discardDeadCode C)
  834.   in
  835.     compileRest (if nargs > 1
  836.                  then (Krestart :: Klabel lbl :: Kgrab (nargs - 1) :: C')
  837.                  else (Klabel lbl :: C'))
  838.   end
  839.   handle Stack.Empty =>
  840.     C
  841. ;
  842.  
  843. fun compileLambda is_pure exp =
  844.   let val () = Stack.clear stillToCompile
  845.       val () = resetLabel()
  846.       val () = resetLabelNot()
  847.       val (qfv, exp') = UNdeBruijn exp (* e -- could check: qfv = 0 *)
  848.       val init_code =
  849.             compileExp nullEnv (Nolabel, 0) 0 0 exp' []
  850.       val function_code =
  851.             compileRest [] 
  852.   in
  853.     { kph_is_pure = is_pure,
  854.       kph_inits   = init_code,
  855.       kph_funcs   = function_code }
  856.   end;
  857.